{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "cddc044d-5d48-4427-aebd-75c608f31c62",
   "metadata": {},
   "source": [
    "# Python中的函数\n",
    "\n",
    "### 认识函数\n",
    "\n",
    "在开始编写具体的函数代码之前，先理解什么是函数以及它为什么如此重要。\n",
    "\n",
    "**函数**是一段组织好的，可重复使用的，用来执行一个特定任务的代码块。函数可以接收输入参数并返回一个结果。\n",
    "\n",
    "函数的好处包括：\n",
    "\n",
    "- **代码复用**：相同的代码不需要在多个地方重写。\n",
    "- **模块化**：大问题可以分解成小的、管理得当的部分来解决。\n",
    "- **简化问题**：复杂的任务可以通过定义函数来简化。\n",
    "\n",
    "### 定义和调用函数\n",
    "\n",
    "接下来，我们将通过几个例子来展示如何定义和调用函数。\n",
    "\n",
    "#### 例子 1：定义一个简单的打招呼函数\n",
    "\n",
    "这个函数接收一个名字作为参数，并返回一个问候语。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "79b063df-5d44-4d12-be99-fb589204110e",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Hello, Alice! How are you?\n"
     ]
    }
   ],
   "source": [
    "# 定义函数\n",
    "def greet(name):\n",
    "    \"\"\"\n",
    "   函数greet接受了一个name参数\n",
    "    \"\"\"\n",
    "    return f\"Hello, {name}! How are you?\"\n",
    "\n",
    "# 调用函数\n",
    "print(greet(\"Alice\"))\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "51a2a7f9-2f58-4603-a8ac-8c2490bc512a",
   "metadata": {},
   "source": [
    "在这个例子中，greet是函数的名称，name是函数接收的参数。函数体是缩进的代码块，它定义了函数的操作。return语句返回最终的问候语。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e8311f6a-969c-4f52-bb62-e6193face4ae",
   "metadata": {},
   "source": [
    "### 函数命名规则\n",
    "\n",
    "- **命名约定**：Python函数名应该是小写字母，如果名称中有多个单词，应使用下划线`_`分隔各个单词。这是PEP 8 —— Python的官方编码风格指南推荐的命名方式。\n",
    "- **含义清晰**：函数名称应该简短且描述性强，让人一看就知道函数的作用。例如，`add`、`subtract`、`calculate_interest`等。\n",
    "- **避免冲突**：函数名不应与Python内置函数和关键字冲突，以免覆盖它们的功能。\n",
    "\n",
    "### 参数规则\n",
    "\n",
    "- **位置参数**：定义函数时列出的参数，调用函数时按照这些参数的顺序传递值。\n",
    "- **默认参数**：在函数定义中给参数指定默认值。调用函数时，可以省略这些参数，此时将使用默认值。\n",
    "- **关键字参数**：在函数调用时，可以通过“键=值”的形式指定参数，这使得函数调用更加清晰。\n",
    "- **可变参数**：使用`*args`（接受任意数量的位置参数）和`**kwargs`（接受任意数量的关键字参数）来让函数接受不确定数量的参数。\n",
    "\n",
    "### 缩进规则\n",
    "\n",
    "- **一致性**：Python中的缩进非常重要，因为它定义了代码块的开始和结束。函数体内的所有语句都必须相对于`def`关键字同样数量的空格进行缩进。\n",
    "- **空格数量**：官方推荐的缩进是4个空格，这是Python社区的普遍约定。使用Tab键或空格键都可以，但不要混用。\n",
    "\n",
    "### `return`的规则\n",
    "\n",
    "- **结束函数**：`return`语句用于从函数中返回值。执行到`return`语句时，函数会立即终止，并将`return`后的表达式的值返回给调用者。\n",
    "- **默认返回值**：如果函数中没有`return`语句，或者`return`后面没有任何表达式，函数默认返回`None`。\n",
    "- **多个返回值**：函数可以返回多个值，这些值会被自动组合成一个元组。\n",
    "\r\n",
    "在Python中，以`f`开头的字符串被称为**f-string**，正式名称为格式化字符串字面量（Formatted String Literals）。从Python 3.6版本开始引入，f-string提供了一种非常方便的方法来嵌入表达式到字符串常量中。\r\n",
    "\r\n",
    "使用f-string时，您只需要在字符串前加上字母`f`，然后在字符串内部的大括号`{}`中直接写入Python表达式。当这个字符串被解析时，大括号内的表达式会被求值，然后表达式的结果会被格式化为字符串并插入到相应的位置。\r\n",
    "\r\n",
    "这是一种非常有效的格式化字符串的方式，因为它简洁明了，易于阅读和编写。\r\n",
    "\r\n",
    "### 示例\r\n",
    "\r\n",
    "假设我们有两个变量，我们想要在一条消息中使用它们的值："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "7a714e65-0156-4136-b23a-6def20b29f4f",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Hello, Alice. You are 30 years old.\n"
     ]
    }
   ],
   "source": [
    "name = \"Alice\"\n",
    "age = 30\n",
    "message = f\"Hello, {name}. You are {age} years old.\"\n",
    "print(message)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e28523c0-69cb-4ff1-8731-91d329b4351c",
   "metadata": {},
   "source": [
    "在这个例子中，{name}和{age}是表达式，它们在字符串被创建时被求值，并且它们的值被插入到字符串中。这样，我们就不需要使用旧式的字符串格式化方法（如%操作符或str.format方法），使得代码更加简洁和直观"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "69ec8614-42f0-4d8e-bcf5-2c9c9a225787",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "两数之和为: 15\n"
     ]
    }
   ],
   "source": [
    "# 定义一个函数，用于计算两个数的和\n",
    "def add(number1, number2):\n",
    "    \"\"\"\n",
    "    将两个数字相加并返回结果。\n",
    "\n",
    "    参数:\n",
    "    number1 (int or float): 第一个数字。\n",
    "    number2 (int or float): 第二个数字。\n",
    "\n",
    "    返回值:\n",
    "    int or float: number1 和 number2 的和。\n",
    "    \"\"\"\n",
    "    # 返回两个参数的和\n",
    "    return number1 + number2\n",
    "\n",
    "# 调用函数并打印结果\n",
    "result = add(10, 5)\n",
    "# 使用f-string打印结果\n",
    "print(f\"两数之和为: {result}\")\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ee3648b5-e4b2-4fe7-9a78-805750f371cf",
   "metadata": {},
   "source": [
    "在这个例子中，我们定义了一个名为add的函数，它接收两个参数：number1和number2，然后返回这两个参数的和。当我们调用add函数时，传递给它两个数字（例如10和5），它就会计算这两个数字的和，并将结果返回。我们将这个返回值存储在变量result中，并使用print函数打印出来。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "650590b7-3df9-4745-9b94-6c3712b264a0",
   "metadata": {},
   "source": [
    "### 位置参数\n",
    "\n",
    "位置参数是最基本的参数类型，调用函数时需要按照函数定义中的参数顺序传递值。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "c88949a5-37f8-408e-aecf-6f8fa77f3d5a",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "我叫李雷，今年30岁。\n"
     ]
    }
   ],
   "source": [
    "# 定义一个函数，接受两个位置参数\n",
    "def introduce(name, age):\n",
    "    print(f\"我叫{name}，今年{age}岁。\")\n",
    "\n",
    "# 按照位置传递参数\n",
    "introduce(\"李雷\", 30)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a109f253-bbbc-4e26-9622-8a3d68bc5bb7",
   "metadata": {},
   "source": [
    "在这个例子中，`introduce`函数定义了两个位置参数：`name`和`age`。调用该函数时，必须按照这个顺序传递参数值。\n",
    "\n",
    "### 默认参数\n",
    "\n",
    "默认参数允许在函数定义时给参数指定一个默认值。如果调用函数时没有传递这些参数，将使用默认值。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "99a15b0c-27a7-4bd7-a843-c80478203606",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "我叫韩梅梅，今年18岁。\n",
      "我叫李雷，今年30岁。\n"
     ]
    }
   ],
   "source": [
    "# 定义一个函数，其中一个参数有默认值\n",
    "def introduce(name, age=18):\n",
    "    print(f\"我叫{name}，今年{age}岁。\")\n",
    "\n",
    "# 只传递name参数，age参数使用默认值\n",
    "introduce(\"韩梅梅\")\n",
    "# 传递两个参数，覆盖默认值\n",
    "introduce(\"李雷\", 30)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f7362332-66e0-4b29-9ca8-7628daf198f3",
   "metadata": {},
   "source": [
    "在这个例子中，`age`参数有一个默认值18。当调用`introduce`函数时，如果没有为`age`提供值，它将自动使用默认值。\n",
    "\n",
    "### 关键字参数\n",
    "\n",
    "关键字参数允许在函数调用时通过参数名来指定参数值，使得代码更加清晰易读。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "97a357fb-5f90-43e1-a6c0-5c6804f64ff3",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "我叫小明，今年22岁。\n"
     ]
    }
   ],
   "source": [
    "# 定义一个函数\n",
    "def introduce(name, age):\n",
    "    print(f\"我叫{name}，今年{age}岁。\")\n",
    "\n",
    "# 使用关键字参数调用函数\n",
    "introduce(age=22, name=\"小明\")\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "17389f2b-5454-4858-afa5-a1fea2eff24f",
   "metadata": {},
   "source": [
    "在这个例子中，即使调用时参数的顺序与定义不同，函数依然可以正确地接收到所有参数的值。\n",
    "\n",
    "### 可变参数\n",
    "\n",
    "使用`*args`和`**kwargs`，函数可以接受不确定数量的位置参数和关键字参数。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "d8a18f88-d40c-45a8-a375-5c2a5b819cb2",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "我叫李雷。\n",
      "我的爱好是： 篮球 游泳 \n",
      "我的信息：\n",
      "年龄: 30\n",
      "职业: 教师\n"
     ]
    }
   ],
   "source": [
    "# 定义一个函数，接受任意数量的位置参数和关键字参数\n",
    "def profile(name, *args, **kwargs):\n",
    "    print(f\"我叫{name}。\")\n",
    "    print(\"我的爱好是：\", end=\" \")\n",
    "    for hobby in args:\n",
    "        print(hobby, end=\" \")\n",
    "    print(\"\\n我的信息：\")\n",
    "    for key, value in kwargs.items():\n",
    "        print(f\"{key}: {value}\")\n",
    "\n",
    "# 调用函数\n",
    "profile(\"李雷\", \"篮球\", \"游泳\", 年龄=30, 职业=\"教师\")\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ce19ad2d-ae89-48c7-b517-c20a4d1b79e1",
   "metadata": {},
   "source": [
    "在这个例子中，*args接受任意数量的位置参数，它们被视为一个元组；**kwargs接受任意数量的关键字参数，这些参数被存储在一个字典中。这使得profile函数非常灵活，能够处理各种不同的参数组合。\n",
    "\n",
    "通过这些例子，我们可以看到Python中参数的多样性和灵活性，从基本的位置参数到更高级的可变参数，使得函数能够以多种方式接受输入数据。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f41a154e-96a7-45b5-9c08-8de618cb8b81",
   "metadata": {},
   "source": [
    "### 例子：组织聚会\r\n",
    "\r\n",
    "假设我们要组织一个聚会，需要记录参加聚会的人的名字（位置参数）和每个人带来的食物（关键字参数）。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "ac284b6d-f9f1-40ac-bbb2-766fe2e2f1ce",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "聚会参加者名单：\n",
      "李雷\n",
      "韩梅梅\n",
      "小明\n",
      "\n",
      "带来的食物：\n",
      "李雷: 蛋糕\n",
      "韩梅梅: 果汁\n",
      "小明: 三明治\n"
     ]
    }
   ],
   "source": [
    "def organize_party(*guests, **foods):\n",
    "    print(\"聚会参加者名单：\")\n",
    "    for guest in guests:\n",
    "        print(guest)\n",
    "    \n",
    "    print(\"\\n带来的食物：\")\n",
    "    for guest, food in foods.items():\n",
    "        print(f\"{guest}: {food}\")\n",
    "\n",
    "# 调用函数\n",
    "organize_party(\"李雷\", \"韩梅梅\", \"小明\", 李雷=\"蛋糕\", 韩梅梅=\"果汁\", 小明=\"三明治\")\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "41ead4de-c15f-41be-9590-86670f9cea24",
   "metadata": {},
   "source": [
    "### 如何区分`*args`和`**kwargs`\n",
    "\n",
    "- *args：表示任意数量的位置参数（未命名参数），它们被打包进一个元组。在函数体内，你通过遍历\n",
    "\n",
    "  args来访问这些参数。\n",
    "\n",
    "  - 在上例中，`\"李雷\", \"韩梅梅\", \"小明\"`是通过`*guests`传入的，`guests`变量在函数内部是一个元组。\n",
    "\n",
    "- **kwargs：表示任意数量的关键字参数（命名参数），它们被打包进一个字典。在函数体内，可以通过关键字来访问每个参数的值。\n",
    "\n",
    "  - 在上例中，`李雷=\"蛋糕\", 韩梅梅=\"果汁\", 小明=\"三明治\"`是通过`**foods`传入的，`foods`变量在函数内部是一个字典，键是参加者的名字，值是他们带来的食物。\n",
    "\n",
    "### 关键点\n",
    "\n",
    "- 使用`*args`时，参数名`args`可以替换成其他名称，但前面的`*`是必需的，它告诉Python这是一个位置参数的集合。\n",
    "- 使用`**kwargs`时，参数名`kwargs`也可以替换，但前面的`**`是必需的，它表明这是一个关键字参数的集合。\n",
    "- 在函数定义中，`*args`必须位于`**kwargs`之前。\n",
    "\n",
    "通过上面的例子和说明，希望能帮助你更清楚地理解`*args`和`**kwargs`的区别及其如何使用。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "d3a5bed5-255d-46df-abf8-0ca3b154c3d7",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "6\n",
      "24\n"
     ]
    }
   ],
   "source": [
    "def calculator(operation, *args):\n",
    "    if operation == \"add\":\n",
    "        return sum(args)\n",
    "    elif operation == \"multiply\":\n",
    "        result = 1\n",
    "        for num in args:\n",
    "            result *= num\n",
    "        return result\n",
    "\n",
    "# 使用可变位置参数\n",
    "print(calculator(\"add\", 1, 2, 3))  # 输出: 6\n",
    "print(calculator(\"multiply\", 1, 2, 3, 4))  # 输出: 24\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "77da3f2d-fab4-4ddc-a651-8688db0c9fc1",
   "metadata": {},
   "source": [
    "## 变量作用域\n",
    "\n",
    "在Python中，变量的作用域决定了在程序的哪些部分可以访问该变量。理解局部变量和全局变量的区别是编写清晰、可维护代码的关键。\n",
    "\n",
    "### 全局变量\n",
    "\n",
    "全局变量是在函数外部定义的变量，它可以在整个程序中被访问和修改。全局变量对于在多个函数之间共享数据非常有用。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "e58bd7c9-db5d-49a1-9dce-169792899123",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "我是全局变量\n"
     ]
    }
   ],
   "source": [
    "x = \"我是全局变量\"\n",
    "\n",
    "def access_global():\n",
    "    # 可以在函数内访问全局变量\n",
    "    print(x)\n",
    "\n",
    "access_global()  # 输出: 我是全局变量\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0b467d4d-98f9-4aeb-a5c7-bb19684d40e2",
   "metadata": {},
   "source": [
    "### 局部变量\n",
    "\n",
    "局部变量是在函数内部定义的变量，它只能在该函数内部被访问。函数的参数也被视为局部变量。使用局部变量可以防止函数之间的数据干扰，使得函数更加独立和可重用。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "id": "9e66c0fc-18cc-47a1-abc3-1d046e3a4b2b",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "我是局部变量\n"
     ]
    }
   ],
   "source": [
    "def demo():\n",
    "    y = \"我是局部变量\"\n",
    "    print(y)\n",
    "\n",
    "demo()  # 输出: 我是局部变量\n",
    "# print(y)  # 这行代码会报错，因为y是一个局部变量，只能在demo函数内部访问\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "72fd474d-4b7e-4d30-a2c4-7ed730a7944f",
   "metadata": {},
   "source": [
    "### 变量作用域的重要性\n",
    "\n",
    "1. **避免命名冲突**：局部变量和全局变量可以有相同的名字而不互相干扰。局部变量的存在可以避免在不同函数或代码块中使用相同名称的变量时产生的命名冲突。\n",
    "2. **内存管理**：局部变量在函数调用时创建，在函数执行结束时销毁。这有助于有效管理程序占用的内存资源。\n",
    "3. **提高程序可读性和可维护性**：通过使用局部变量，可以清晰地看到每个函数使用和操作的变量，从而提高代码的可读性和可维护性。\n",
    "\n",
    "### 修改全局变量\n",
    "\n",
    "在函数内部修改全局变量时，需要使用`global`关键字声明变量。这告诉Python解释器：在这个函数中，我们打算使用的是全局变量而不是创建一个新的局部变量。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "id": "93e35aa4-2344-4ae6-8bfb-5a4d5ba5a62e",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "20\n"
     ]
    }
   ],
   "source": [
    "z = 10\n",
    "\n",
    "def modify_global_var():\n",
    "    global z\n",
    "    z = 20  # 修改全局变量\n",
    "\n",
    "modify_global_var()\n",
    "print(z)  # 输出: 20\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "db3fa099-571b-4342-8d2c-c955754f861c",
   "metadata": {},
   "source": [
    "理解局部变量和全局变量的作用域是Python编程的基础。正确地使用这两种变量可以帮助你编写出更加清晰、可维护且高效的代码。在实践中，推荐尽可能使用局部变量来避免不必要的全局状态，以减少潜在的错误和复杂性。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d2290549-ccf5-4e35-bce7-1aa5f0b686a7",
   "metadata": {},
   "source": [
    "### `global`关键字的用法\n",
    "\n",
    "`global`关键字用于在函数内部修改全局变量。如果不使用`global`关键字，赋值操作会将变量视为局部变量。\n",
    "\n",
    "#### 示例："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "id": "dcae1450-7b6b-4672-8d5a-12ba01972f0d",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "10\n"
     ]
    }
   ],
   "source": [
    "x = 5\n",
    "\n",
    "def modify_global_var():\n",
    "    global x  # 声明x为全局变量\n",
    "    x = 10\n",
    "\n",
    "modify_global_var()\n",
    "print(x)  # 输出: 10\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a8f223d1-1b7b-4a1b-962b-16a330813e84",
   "metadata": {},
   "source": [
    "### `nonlocal`关键字的用法\n",
    "\n",
    "`nonlocal`关键字用于在嵌套的函数中修改外层函数的局部变量。\n",
    "\n",
    "#### 示例："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "id": "33667e17-454e-4ec1-aab7-921d3926766d",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "修改外部变量\n"
     ]
    }
   ],
   "source": [
    "def outer():\n",
    "    x = \"外部变量\"\n",
    "    def inner():\n",
    "        nonlocal x  # 声明x为外层函数的局部变量\n",
    "        x = \"修改外部变量\"\n",
    "    inner()\n",
    "    print(x)\n",
    "\n",
    "outer()  # 输出: 修改外部变量\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "21647de4-f87a-42da-8699-8d1e335e351f",
   "metadata": {},
   "source": [
    "## 递归函数\n",
    "\n",
    "递归函数是一种自我调用的函数，它允许函数将解决问题的任务分解成更小的子任务，这些子任务的结构和原始任务相似但规模更小。递归函数是处理数据结构（如树和图）、执行排序算法和解决复杂问题的强大工具。\n",
    "\n",
    "### 递归函数的关键组成部分\n",
    "\n",
    "1. **基本情况（Base Case）**：递归过程必须有一个或多个基本情况，它们不需要递归就可以直接解决。基本情况防止无限递归，为递归提供终止点。\n",
    "2. **递归步骤（Recursive Step）**：在这一步，函数通过调用自身来解决子任务。每次递归调用应该使问题向基本情况靠近。\n",
    "\n",
    "### 递归函数的特点\n",
    "\n",
    "- **简化问题解决**：通过将大问题分解为相似的小问题，递归使得编程解决复杂问题更加简单。\n",
    "- **优雅的代码**：递归函数通常比等价的非递归函数更简洁、更易于理解。\n",
    "- **高效的数据结构操作**：递归非常适合操作树形或图形数据结构，例如遍历或搜索。\n",
    "\n",
    "### 注意事项\n",
    "\n",
    "- **栈溢出**：由于每次函数调用都会在内存的调用栈中占用空间，递归过深可能导致栈溢出错误。\n",
    "- **性能问题**：某些情况下，递归可能不是性能最优的解决方案，尤其是当存在大量重复计算时。在这些情况下，可以考虑使用循环或动态规划等技术。\n",
    "\n",
    "### 示例：阶乘函数\n",
    "\n",
    "阶乘是最经典的递归函数示例之一，因为它有明确的基本情况和递归步骤。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "id": "dcf27b4a-aa41-4ea6-baec-ad3423c4af12",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "120\n"
     ]
    }
   ],
   "source": [
    "def factorial(n):\n",
    "    # 基本情况：0! = 1\n",
    "    if n == 0:\n",
    "        return 1\n",
    "    # 递归步骤：n! = n * (n-1)!\n",
    "    else:\n",
    "        return n * factorial(n - 1)\n",
    "\n",
    "# 使用递归函数计算5的阶乘\n",
    "print(factorial(5))  # 输出: 120\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2c5abafc-3121-43a6-9eb2-7357e137c32f",
   "metadata": {},
   "source": [
    "在这个例子中，factorial函数通过递归调用自身来计算阶乘。当n为0时，它直接返回1，这是基本情况。对于所有其他情况，函数通过将n乘以n-1的阶乘来计算阶乘，这是递归步骤。每次递归调用都会使问题的规模减小，直到达到基本情况。\n",
    "递归是一种强大的编程技术，它能够简化复杂问题的解决方法，使代码更加简洁和优雅。理解递归的基本原理和如何正确地使用递归对于成为一名高效的程序员至关重要。在使用递归时，始终要确保定义了清晰的基本情况，并且每次递归调用都在向基本情况靠近，以避免无限递归和栈溢出的问"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ca5437c3-2fbc-4c87-ab6d-e6b56aaaddc6",
   "metadata": {},
   "source": [
    "# 匿名函数\n",
    "\n",
    "匿名函数，在Python中通常是指通过`lambda`关键字创建的函数。`lambda`函数是一种简洁的定义函数的方式，用于创建小型的、一次性使用的函数对象。由于它们不需要标准的`def`函数定义语法，因此在需要函数对象的地方，尤其是在函数式编程模式中，`lambda`函数非常有用。\n",
    "\n",
    "### 基本语法\n",
    "\n",
    "`lambda`函数的基本语法如下："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "id": "053b1f20-1be8-436f-9862-49fd0b4d54c7",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<function __main__.<lambda>(arguments)>"
      ]
     },
     "execution_count": 19,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "lambda arguments: expression"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "93bcd284-7c87-494d-8bfd-23ee7e101b51",
   "metadata": {},
   "source": [
    "这里：\n",
    "\n",
    "- `arguments`是函数的参数列表，参数之间用逗号分隔。\n",
    "- `expression`是一个表达式，它在函数被调用时求值，并且其结果就是函数的返回值。\n",
    "\n",
    "### 特点\n",
    "\n",
    "- **简洁**：`lambda`函数通常只有一行，适用于编写简单的函数。\n",
    "- **匿名**：`lambda`函数没有名称，这是它们被称为“匿名函数”的原因。\n",
    "- **一次性**：通常用于不会在别处再次复用的小型函数。\n",
    "- **灵活性**：可以用在高阶函数中，如`map()`, `filter()`, 和`sorted()`等，作为参数传递。\n",
    "\n",
    "### 示例\n",
    "\n",
    "#### 示例 1：简单的`lambda`函数"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "id": "07271c57-7b10-4bed-b56f-739fc81a2049",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "5\n"
     ]
    }
   ],
   "source": [
    "# 使用lambda定义一个函数，返回两数之和\n",
    "add = lambda x, y: x + y\n",
    "\n",
    "# 调用函数\n",
    "print(add(2, 3))  # 输出: 5\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e2c8a61d-4a9d-4b2b-a89e-b7cd923c5fd4",
   "metadata": {},
   "source": [
    "在这个例子中，lambda x, y: x + y创建了一个接受两个参数的匿名函数，并返回它们的和。\n",
    "\n",
    "示例 2：结合map()使用\n",
    "map()函数接受一个函数和一个列表，将该函数应用于列表中的每个元素。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "id": "512c05fe-a31d-49cd-b026-d5b6f09829b4",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[2, 4, 6, 8, 10]\n"
     ]
    }
   ],
   "source": [
    "# 使用lambda函数将列表中的每个元素乘以2\n",
    "numbers = [1, 2, 3, 4, 5]\n",
    "doubled_numbers = map(lambda x: x * 2, numbers)\n",
    "\n",
    "# 将map对象转换为列表并打印\n",
    "print(list(doubled_numbers))  # 输出: [2, 4, 6, 8, 10]\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5b85213a-beeb-46f1-b876-dda9d7c11490",
   "metadata": {},
   "source": [
    "示例 3：结合filter()使用\n",
    "filter()函数用于过滤序列，过滤掉不符合条件的元素。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "id": "d3661b6a-1930-41a8-9281-a978fb430be3",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[2, 4, 6]\n"
     ]
    }
   ],
   "source": [
    "# 使用lambda函数过滤出列表中的偶数\n",
    "numbers = [1, 2, 3, 4, 5, 6]\n",
    "even_numbers = filter(lambda x: x % 2 == 0, numbers)\n",
    "\n",
    "# 将filter对象转换为列表并打印\n",
    "print(list(even_numbers))  # 输出: [2, 4, 6]\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a91e0b8b-b629-4f70-9484-8bb701a42502",
   "metadata": {},
   "source": [
    "### 使用场景\n",
    "\n",
    "`lambda`函数通常用在需要简单函数的场合，特别是在排序或数据过滤等操作中，当这些操作需要一个小的函数作为参数时，使用`lambda`可以让代码更加清晰和简洁。\n",
    "\n",
    "### 总结\n",
    "\n",
    "`lambda`函数提供了一种快捷的定义轻量级函数的方法，特别适合于简单的操作，如算术运算、字符串操作等。虽然它们在功能上比标准的`def`定义的函数受限，但在合适的场合使用`lambda`函数可以使代码更加优雅。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "e7838c5a-bf22-4af8-815c-54ec71fa7619",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.13"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
